#ifndef ODBC_DETAILS_BINDABLE_BUFFER_BASE_HPP
#define ODBC_DETAILS_BINDABLE_BUFFER_BASE_HPP

#include "odbc/odbc_config.hpp"
#include "odbc/details/os_sql_wrapper.hpp"
#include <boost/any.hpp>

namespace odbc
{
class statement;

namespace details
{

/// \ingroup OdbcLibrary
/// \internal
///	\brief This is the base class for all the buffer classes that are used to put or get the values in an ODBC 
///		statement, as parameters or columns.
class ODBC_DECL bindable_buffer_base
{
public:
	/// \brief It initializes the field value status to NULL data and makes the binding position invalid. The binding 
	///		position will be set to a valid value only when the column buffer is bound to the statement.
	bindable_buffer_base();

	/// \brief It does nothing. It is just declared virtual, to avoid resource leaking.
	virtual ~bindable_buffer_base();

	/// \return true if the buffer contains a null value, by checking the bound length indicator.
	bool is_null() const 
	{ 
		return lengthIndicator_ == SQL_NULL_DATA; 
	}

	/// \brief Subclasses should provide the address of the buffer containing the fetched value. The returned address 
	///		should not unnecessarily be the address of the bound buffer (this case usually applies to variable length 
	///		fields).
	/// \return the address of the buffer contained the fetched value.
	virtual const void* buffer() const = 0;

	/// \brief It returns the value contained in the buffer. If the buffer has \c NULL value, it returns an empty 
	///		\code boost::any \endcode object.
	virtual boost::any value() const = 0;

	///	\brief  It sets the value to the bound buffer.
	/// \param val The value to be bound to the buffer.
	/// \exception boost::bad_any_cast If the specified value is not compatible with the C++ type supported by the bound 
	///		buffer.
	virtual void set_value( const boost::any& val) = 0;

	///	\brief It binds this buffer to the statement, at the specified position.
	/// \param stat the statement to which the buffer should be bound.
	/// \param bindPosition the position the buffer should be bound at (it can be either the index of the column, or the 
	///		index of the parameter, depending on which statement is bound).
	/// \note Depending on the usage of the buffer (column or parameter) and the type of the value to be fetched (fixed 
	///		size type or variable size type), this method should implement binding in a different way, so the method is 
	///		pure virtual at this level.
	virtual void bind( statement& stat, SQLUSMALLINT bindPosition) = 0;

	/// \brief It retrieves the position to which the buffer is bound.
	/// \return the position in the data set record to which the buffer is bound.
	unsigned short bind_position() const 
	{ 
		return (unsigned short)bindPosition_; 
	}

protected:
	/// \brief It stores the length of the fetched data or the null indicator, if the fetch value was null.
	SQLLEN lengthIndicator_;

	/// \brief It stores the number of the column in the dataset record or parameter in the statement the buffer is 
	///		bound to.
	SQLUSMALLINT bindPosition_;

protected:
	/// \brief It extracts the handle from the specified statement object. Since only \c bindable_buffer_base class has 
	///		access to the private data members of \c statement class (declared as friend), this method can be used by 
	///		the subclasses of \c bindable_buffer_base class to retrieve the statement handle.
	static SQLHANDLE statement_handle( const statement& stat);
};


} // namespace details
} // namespace odbc

#endif // ODBC_DETAILS_BINDABLE_BUFFER_BASE_HPP
